﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Web;

namespace LY.Common.Utils.Sf_Struct
{
    public class MySign
    {
        private static string _privateKey = ConfigurationManager.AppSettings["PrivateKey"];//私钥
        private static string _publicKey = ConfigurationManager.AppSettings["PublicKey"];//公钥

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct BLOBHEADER
        {
            public byte bType;      //PRIVATEKEYBLOB = 0x7
            public byte bVersion;   //Digital Signature Standard=3; CUR_BLOB_VERSION=2
            public short reserved;  //
            public uint aiKeyAlg;   //CALG_RSA_KEYX=0xa400; CALG_RSA_SIGN=0x2400
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct RSAPUBKEY
        {
            public int magic;       //0x32415352 ("RSA2") for public/private key; ("RSA1") for public key only
            public int bitlen;      //Number of bits in the modulus. A multiple of eight.
            public int pubexp;      //The public exponent
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct PRIVATEKEYBLOB
        {
            public BLOBHEADER blobheader;
            public RSAPUBKEY rsapubkey;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
            public byte[] modulus;          //[rsapubkey.bitlen/8];  as Modulus
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
            public byte[] prime1;           //[rsapubkey.bitlen/16]; as P
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
            public byte[] prime2;           //[rsapubkey.bitlen/16]; as Q
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
            public byte[] exponent1;        //[rsapubkey.bitlen/16]; as D mod (P - 1)".
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
            public byte[] exponent2;        //[rsapubkey.bitlen/16]; as D mod (Q - 1)".
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
            public byte[] coefficient;      //[rsapubkey.bitlen/16]; as InverseQ
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
            public byte[] privateExponent;  //[rsapubkey.bitlen/8];  as D

            public RSAParameters GetRSAKey()
            {
                RSAParameters key = new RSAParameters()
                {
                    Modulus = this.modulus,
                    P = this.prime1,
                    Q = this.prime2,
                    DP = this.exponent1,
                    DQ = this.exponent2,
                    InverseQ = this.coefficient,
                    D = this.privateExponent,
                    Exponent = BitConverter.GetBytes(this.rsapubkey.pubexp),
                };
                Array[] arrays = { key.Modulus, key.P, key.Q, key.DP, key.DQ, key.InverseQ, key.D, key.Exponent };
                foreach (Array a in arrays)
                {
                    Array.Reverse(a);
                }
                return key;
            }

            public static RSAParameters LoadFromSNK(string filename)
            {
                byte[] raw = File.ReadAllBytes(filename);
                if (raw.Length != Marshal.SizeOf(typeof(PRIVATEKEYBLOB)))
                {
                    throw new InvalidOperationException("not a valid snk file with public/private key");
                }
                GCHandle gc = GCHandle.Alloc(raw, GCHandleType.Pinned);
                PRIVATEKEYBLOB b = (PRIVATEKEYBLOB)Marshal.PtrToStructure(gc.AddrOfPinnedObject(), typeof(PRIVATEKEYBLOB));
                gc.Free();
                return b.GetRSAKey();
            }
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct PUBLICKEYBLOB
        {
            //.Net wrapper
            public int signatureAlg;             //CALG_RSA_SIGN=0x2400
            public int hashAlg;                  //CALG_SHA1=0x8004
            public int blobLength;               //148

            public BLOBHEADER blobheader;
            public RSAPUBKEY rsapubkey;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
            public byte[] modulus;               //[rsapubkey.bitlen/8];  as Modulus

            public RSAParameters GetRSAKey()
            {
                RSAParameters key = new RSAParameters()
                {
                    Modulus = this.modulus,
                    Exponent = BitConverter.GetBytes(this.rsapubkey.pubexp),
                };
                Array[] arrays = { key.Modulus, key.Exponent };
                foreach (Array a in arrays)
                {
                    Array.Reverse(a);
                }
                return key;
            }

            public static RSAParameters LoadFromSNK(string filename)
            {
                byte[] raw = File.ReadAllBytes(filename);
                string temp = Encoding.Default.GetString(raw);
                if (raw.Length != Marshal.SizeOf(typeof(PUBLICKEYBLOB)))
                {
                    throw new InvalidOperationException("not a valid snk file with public/private key");
                }
                GCHandle gc = GCHandle.Alloc(raw, GCHandleType.Pinned);
                PUBLICKEYBLOB b = (PUBLICKEYBLOB)Marshal.PtrToStructure(gc.AddrOfPinnedObject(), typeof(PUBLICKEYBLOB));
                gc.Free();
                return b.GetRSAKey();
            }
        }

        //返回算法加密后的字符串
        public string GetSign(string strOrigin)
        {
            //string path = HttpContext.Current.Server.MapPath(@"/App_Data/private_key_platform.snk");
            string path = HttpContext.Current.Server.MapPath(@"/App_Data/" + _privateKey);
            RSAParameters rsa1 = PRIVATEKEYBLOB.LoadFromSNK(path);
            RSACryptoServiceProvider rasss = new RSACryptoServiceProvider();
            rasss.ImportParameters(rsa1);
            //将要签名的要素转化为byte[]
            byte[] data = Encoding.UTF8.GetBytes(strOrigin);
            //md5 你懂的 返回byte[]
            byte[] bb = rasss.SignData(data, "MD5");
            //先将字节数组装化为字符串
            string strbb = Convert.ToBase64String(bb);
            return strbb; 
        }

        //使用公钥验证,没错就是验证而已,这里的公钥是由盛付通提供的。
        public bool ValidateSign(string queryString, string sign)
        {
            string path = HttpContext.Current.Server.MapPath(@"/App_Data/" + _publicKey);
            //string path = HttpContext.Current.Server.MapPath(@"/App_Data/public_key_shengpay(沙箱20141216).snk");
            RSAParameters rsa1 = PUBLICKEYBLOB.LoadFromSNK(path);
            System.Security.Cryptography.RSACryptoServiceProvider rasss = new RSACryptoServiceProvider();
            rasss.ImportParameters(rsa1);
            byte[] signature = Convert.FromBase64String(sign);
            byte[] data = Encoding.UTF8.GetBytes(queryString);
            bool a = rasss.VerifyData(data, "MD5", signature);
            return a;
        }
    }
}
